/*
 * vim:foldmethod=marker:
 */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdint.h>

/* {{{ sadfawerawefdsf
struct queue {
	int	*data;
	int	head;
	int	size;
	int	size_max;
};

struct Node {
	int x;
	struct Node *next;
};

struct adjl {
	struct Node	*first;
	struct Node	*last;
	short int	size;
	uint8_t		visited;

	int		dist;
	int		prev;
};

void
queue_init(struct queue *q, int size)
{
	q->data = (int *) calloc(size, sizeof *q->data);
	q->head = 0;
	q->size = 0;
	q->size_max = size;
}

void
enqueue(struct queue *q, int x)
{
	if (q->size >= q->size_max)
		fprintf(stderr, "queue overflow. failed to add x=%d\n", x);
	else
		q->data[(q->head + q->size++) % q->size_max] = x;
}

int
dequeue(struct queue *q)
{
	int ret = q->data[q->head % q->size_max];
	if (!q->size)
		return ret; *//* a.k.a. UB *//*
	--q->size;
	if (++q->head == q->size_max)
		q->head = 0;
	return ret;
}

unsigned char
queue_isempty(struct queue *q)
{
	return (q->size > 0) ? 0 : 1;
}

void
pushback(struct adjl *al, int x, int edge_i)
{
	struct Node *newnode;

	newnode = (struct Node *) calloc(1UL, sizeof (struct Node));
	newnode->x        = x;
	newnode->is_valid = 1;
	newnode->edge_i   = edge_i;
	newnode->next     = NULL;
	if (!al->first)
		al->first = newnode;
	else
		al->last->next = newnode;
	al->last = newnode;
	al->size++;
}

void
free_al(struct adjl *al)
{
	struct Node *n, *p;
	p = n = al->first;
	while (n) {
		n = n->next;
		free(p);
		p = n;
	}
}

int
build_graph(int s[100][100], const int n, const int m, struct adjl *al)
{
	int i, j;

	for (i = 0; i < n; i++)
		for (j = 0; j < m; j++) {
		}
}

int
mark_area_bfs(struct adjl *al, const int row, const int col, struct queue *q)
{
}
 * }}} */

int
ps(const int s[100][100], const int n, const int m)
{
	int i, j;

	for (i = 0; i < n; i++) {
		for (j = 0; j < m; j++)
			fputc('0' + s[i][j], stderr);
		fputc('\n', stderr);
	}

	return 0;
}

int
mark_area(int s[100][100], const int n, const int m, int row, int col)
{
	int area = 0;
	int i = row, j = col;

	while (j < m && s[i][j] == 0) {
		s[i][j] = 2;
		area++;

		if (i > 0 && s[i - 1][j] == 0)
			area += mark_area(s, n, m, i - 1, j);
		if (i + 1 < n && s[i + 1][j] == 0)
			area += mark_area(s, n, m, i + 1, j);

		j++;
	}

	j = col - 1;
	while (j >= 0 && s[i][j] == 0) {
		s[i][j] = 2;
		area++;

		if (i > 0 && s[i - 1][j] == 0)
			area += mark_area(s, n, m, i - 1, j);
		if (i + 1 < n && s[i + 1][j] == 0)
			area += mark_area(s, n, m, i + 1, j);

		j--;
	}

	return area;
}

static int
revnumcmpp(const void *p1, const void *p2)
{
	return (* (const int *) p2 - * (const int *) p1);
}

int
main(int argc, char **argv)
{
	int n, m, c;
	static int slices[100][100];
	int i = 0, j = 0, k = 0;
	static int area[100 * 100 / 2 + 1];

	scanf("%d%d", &n, &m);
	while (c = fgetc(stdin), c != EOF) {
		if (!isdigit(c))
			continue;
		if (j == m) {
			i++;
			if (i == n) break;
			j = 0;
		}
		slices[i][j] = c - '0';
		j++;
	}

	for (i = 0; i < n; i++) {
		for (j = 0; j < m; j++) {
			if (slices[i][j] == 0) {
				area[k++] = mark_area(slices, n, m, i, j);
				/* ps(slices, n, m);
				 * fputc('\n', stderr); */
			}
		}
	}

	qsort(area, (size_t) k, sizeof area[0], revnumcmpp);

	for (i = 0; i < k; i++)
		printf("%d ", area[i]);
	fputc('\n', stdout);

	return 0;
}
